msg_tool\scripts\entis_gls\csx/
mod.rs1mod base;
6mod v1;
7mod v2;
8
9use crate::ext::io::*;
10use crate::scripts::base::*;
11use crate::types::*;
12use crate::utils::encoding::*;
13use anyhow::Result;
14use base::ECSImage;
15use v1::ECSExecutionImageV1;
16use v2::ECSExecutionImageV2;
17
18#[derive(Clone, Copy, Debug, clap::ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
19pub enum CSXScriptVersion {
21 V1,
23 V2,
25}
26
27#[derive(Clone, Copy, Debug, clap::ValueEnum, PartialEq, Eq, PartialOrd, Ord)]
28pub enum CSXScriptV2FullVer {
30 V2,
32 V3,
35}
36
37#[derive(Debug)]
38pub struct CSXScriptBuilder {}
39
40impl CSXScriptBuilder {
41 pub fn new() -> Self {
42 Self {}
43 }
44}
45
46impl ScriptBuilder for CSXScriptBuilder {
47 fn default_encoding(&self) -> Encoding {
48 Encoding::Utf16LE
49 }
50
51 fn build_script(
52 &self,
53 buf: Vec<u8>,
54 _filename: &str,
55 _encoding: Encoding,
56 _archive_encoding: Encoding,
57 config: &ExtraConfig,
58 _archive: Option<&Box<dyn Script>>,
59 ) -> Result<Box<dyn Script>> {
60 Ok(Box::new(CSXScript::new(buf, config)?))
61 }
62
63 fn extensions(&self) -> &'static [&'static str] {
64 &["csx"]
65 }
66
67 fn script_type(&self) -> &'static ScriptType {
68 &ScriptType::EntisGlsCsx
69 }
70
71 fn is_this_format(&self, _filename: &str, buf: &[u8], buf_len: usize) -> Option<u8> {
72 if buf_len >= 8 && &buf[0..8] == b"Entis\x1a\0\0" {
73 Some(30)
74 } else {
75 None
76 }
77 }
78}
79
80#[derive(Debug)]
81pub struct CSXScript {
82 img: Box<dyn ECSImage>,
83 disasm: bool,
84 custom_yaml: bool,
85}
86
87impl CSXScript {
88 pub fn new(buf: Vec<u8>, config: &ExtraConfig) -> Result<Self> {
89 let reader = MemReader::new(buf);
90 let img = if let Some(ver) = &config.entis_gls_csx_ver {
91 match ver {
92 CSXScriptVersion::V1 => {
93 Box::new(ECSExecutionImageV1::new(reader.to_ref(), config)?)
94 as Box<dyn ECSImage>
95 }
96 CSXScriptVersion::V2 => {
97 Box::new(ECSExecutionImageV2::new(reader.to_ref(), config)?)
98 as Box<dyn ECSImage>
99 }
100 }
101 } else {
102 match ECSExecutionImageV1::new(reader.to_ref(), config) {
103 Ok(img) => Box::new(img),
104 Err(_) => Box::new(ECSExecutionImageV2::new(reader.to_ref(), config)?)
105 as Box<dyn ECSImage>,
106 }
107 };
108 Ok(Self {
109 img,
110 disasm: config.entis_gls_csx_disasm,
111 custom_yaml: config.custom_yaml,
112 })
113 }
114}
115
116impl Script for CSXScript {
117 fn default_output_script_type(&self) -> OutputScriptType {
118 OutputScriptType::Json
119 }
120
121 fn is_output_supported(&self, _output: OutputScriptType) -> bool {
122 true
123 }
124
125 fn default_format_type(&self) -> FormatOptions {
126 FormatOptions::None
127 }
128
129 fn extract_messages(&self) -> Result<Vec<Message>> {
130 self.img.export()
131 }
132
133 fn import_messages<'a>(
134 &'a self,
135 messages: Vec<Message>,
136 file: Box<dyn WriteSeek + 'a>,
137 _filename: &str,
138 _encoding: Encoding,
139 replacement: Option<&'a ReplacementTable>,
140 ) -> Result<()> {
141 self.img.import(messages, file, replacement)
142 }
143
144 fn multiple_message_files(&self) -> bool {
145 true
146 }
147
148 fn extract_multiple_messages(&self) -> Result<std::collections::HashMap<String, Vec<Message>>> {
149 self.img.export_multi()
150 }
151
152 fn import_multiple_messages<'a>(
153 &'a self,
154 messages: std::collections::HashMap<String, Vec<Message>>,
155 file: Box<dyn WriteSeek + 'a>,
156 _filename: &str,
157 _encoding: Encoding,
158 replacement: Option<&'a ReplacementTable>,
159 ) -> Result<()> {
160 self.img.import_multi(messages, file, replacement)
161 }
162
163 fn custom_output_extension<'a>(&'a self) -> &'a str {
164 if self.disasm {
165 "d.txt"
166 } else if self.custom_yaml {
167 "yaml"
168 } else {
169 "json"
170 }
171 }
172
173 fn custom_export(&self, filename: &std::path::Path, encoding: Encoding) -> Result<()> {
174 if self.disasm {
175 let file = crate::utils::files::write_file(filename)?;
176 let file = std::io::BufWriter::new(file);
177 self.img.disasm(Box::new(file))?;
178 } else {
179 let messages = self.img.export_all()?;
180 let s = if self.custom_yaml {
181 serde_yaml_ng::to_string(&messages)?
182 } else {
183 serde_json::to_string_pretty(&messages)?
184 };
185 let s = encode_string(encoding, &s, false)?;
186 let mut file = crate::utils::files::write_file(filename)?;
187 file.write_all(&s)?;
188 }
189 Ok(())
190 }
191
192 fn custom_import<'a>(
193 &'a self,
194 custom_filename: &'a str,
195 file: Box<dyn WriteSeek + 'a>,
196 _encoding: Encoding,
197 output_encoding: Encoding,
198 ) -> Result<()> {
199 if self.disasm {
200 Err(anyhow::anyhow!(
201 "Importing from disassembly is not supported."
202 ))
203 } else {
204 let data = crate::utils::files::read_file(custom_filename)?;
205 let s = decode_to_string(output_encoding, &data, false)?;
206 let messages: Vec<String> = if self.custom_yaml {
207 serde_yaml_ng::from_str(&s)?
208 } else {
209 serde_json::from_str(&s)?
210 };
211 self.img.import_all(messages, file)?;
212 Ok(())
213 }
214 }
215}